package hk.org.ha.cdars;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

import hk.org.ha.cdars.datacontext.BisDataContext.Criteria;
import hk.org.ha.cdars.datacontext.BisDataContext.G1CriterialNode;
import hk.org.ha.cdars.datacontext.BisDataContext.G2CriterialNode;
import hk.org.ha.cdars.datacontext.BisDataContextImpl;
import lava.rt.common.IoCommon;
import lava.rt.common.IoCommon.DirWatcher;
import lava.rt.wrapper.LoggerWrapper;


@SpringBootApplication
public class BisDataImportMain {

	private static ExecutorService executor = Executors.newFixedThreadPool(3) ;
	
	static CountDownLatch countDownLatch=new CountDownLatch(1);
	
	private static LoggerWrapper console=LoggerWrapper.CONSOLE;
	
	private static String G1_LOG_DIR="F:\\g1_log"
			, G2_LOG_DIR="F:\\g2_log"
			;
	
	
	private static Map<String,Long> G1_PATH_ID_MAP=new HashMap<>()
			, G2_PATH_ID_MAP=new HashMap<>()
			;
	
	
	private static Criteria CR=BisDataContextImpl.CRITERIA;
	
	private static <N> N parseCriterialNode(String line,Class<N> cls) {
        
		    N ret=null;
		    
		    if(line==null||line.trim().length()<=0)return ret;
		    println("import "+line);
		    JSONObject row=new JSONObject();
            String[] sens = line.split("path=");
            if(sens.length<2) return ret;
            String path=sens[1];
            String kvs=sens[0];
            
            for(String kv : kvs.split(";")) {
            	String[] _kv=kv.split("=");
            	if(_kv.length<2)continue;
            	String k=_kv[0].trim();
            	String v=_kv[1].trim();
            	row.put(k, v);
            }
            
            row.put("path", path);
            
           // println("j:"+row.toJSONString());
            
            ret=JSONArray.parseObject(row.toJSONString(),cls);
            return ret;
        
	}
	
	private static void println(String...vals) {
		// TODO Auto-generated method stub
		System.out.println(String.join(",", vals));
	}

	private static <N> List<N> readCriterialNode(File file,Class<N> cls) throws IOException{
		List<N> rets=new ArrayList<>();
		List<String> lines = IoCommon.readLines(file);
				//Files.readAllLines(Paths.get(file.getPath()), StandardCharsets.UTF_8);
		for(String line :lines) {
			N ret=parseCriterialNode(line, cls);
			rets.add(ret);
		}
		return rets;
	}
	
	
	
	
	
	public static void main(String[] args) throws Exception {
		
		ApplicationContext context =SpringApplication.run(BisDataImportMain.class, args);
		
		executor.execute(listenG1Log(context));
		
		executor.execute(listenG2Log(context));
		countDownLatch.await();
		
	}

	
	
	private static Runnable listenG1Log(ApplicationContext context) throws Exception {
		BisDataContextImpl dataContext=context.getBean(BisDataContextImpl.class);
		
		dataContext.G1_CRITERIAL_NODE.selectCursoring((index,node)->{
			G1_PATH_ID_MAP.put(node.getPath(), node.getId());
			return 0;
		},"",CR.criteriaType.asc );
		
		// TODO Auto-generated method stub
        Runnable ret= IoCommon.runWatchingDir(new DirWatcher(new File(G1_LOG_DIR),false) {
			
			@Override
			protected void onEntryModify(File file) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			protected void onEntryDelete(File file) {
				// TODO Auto-generated method stub
				println("delete "+file.getPath());
			}
			
			@Override
			protected void onEntryCreate( File file) {
				// TODO Auto-generated method stub
				String path=file.getPath();
				println("find "+path);
				
				try {
					Thread.sleep(2000);
					int i=0,u=0;
					List<G1CriterialNode> nodes=readCriterialNode(file, G1CriterialNode.class);
					nodes=nodes.stream().filter(n->n!=null).collect(Collectors.toList());
					for(G1CriterialNode node :nodes) {
						
						String key=node.getPath();
						if(G1_PATH_ID_MAP.containsKey(key)) {
							Long id=G1_PATH_ID_MAP.get(key);
							if (id!=null) {
								node.setId(id);
								//dataContext.updateEntity(node);
								u++;
							}
						}else {
							node.setFromPath(path);
							node.setRemark("");
							dataContext.addEntity(node);
							i++;
							G1_PATH_ID_MAP.put(key, null);
						}
						
	
					}
					println("finish g1 lines:"+nodes.size()+",inserts:"+i+",updates"+u);
					file.delete();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
        return ret;
	}
	
	
	private static Runnable listenG2Log(ApplicationContext context) throws Exception {
		BisDataContextImpl dataContext=context.getBean(BisDataContextImpl.class);
		
		dataContext.G2_CRITERIAL_NODE.selectCursoring((index,node)->{
			G2_PATH_ID_MAP.put(node.getPath(), node.getId());
			return 0;
		},"",CR.criteriaType.asc );
		
		// TODO Auto-generated method stub
		Runnable ret= IoCommon.runWatchingDir(new DirWatcher(new File(G2_LOG_DIR),false) {
			
			@Override
			protected void onEntryModify(File file) {
				// TODO Auto-generated method stub
				
			}
			
			@Override
			protected void onEntryDelete(File file) {
				// TODO Auto-generated method stub
				println("delete "+file.getPath());
			}
			
			@Override
			protected void onEntryCreate(File file) {
				// TODO Auto-generated method stub
				// TODO Auto-generated method stub
				String path=file.getPath();
				println("find "+path);
				
				try {
					Thread.sleep(2000);
					int i=0,u=0;
					List<G2CriterialNode> nodes=readCriterialNode(file, G2CriterialNode.class);
					nodes=nodes.stream().filter(n->n!=null).collect(Collectors.toList());
					for(G2CriterialNode node :nodes) {
						
						String key=node.getPath();
						if(G2_PATH_ID_MAP.containsKey(key)) {
							Long id=G2_PATH_ID_MAP.get(key);
							if (id!=null) {
								node.setId(id);
								dataContext.updateEntity(node);
								u++;
							}
						}else {
							node.setFromPath(path);
							node.setRemark("");
							dataContext.addEntity(node);
							i++;
							G2_PATH_ID_MAP.put(key, null);
						}
						
	
					}
					println("finish g2 lines:"+nodes.size()+",inserts:"+i+",updates"+u);
					file.delete();
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
		return ret;
	}

}
